import pandas as pd


def gcd(a, b):
    if a == 0:
        return b
    if b == 0:
        return a
    return gcd(b, a % b)


def test_1():


    print("""
    ==============================================
    New example
    ==============================================
    """)
    # public key of alice as e, and private key as d, total encode space is N
    e_alice = 79
    d_alice = 1019
    N_alice = 3337

    o1 = 1
    o2 = 10

    I_alice = 5
    for J_bob in [6, 7, 3]:
        print("\n****************************************************")
        print("J_bob =", J_bob, "; I_alice =", I_alice)

        assert o1 < I_alice < o2
        assert o1 < J_bob < o2

        # ------------------------------
        x_random_bob = 473  # bob's random number
        c = (x_random_bob ** e_alice) % N_alice
        transfer_to_alice = c - J_bob
        print('transfer_to_alice', transfer_to_alice)

        range_alice = [1, o2 - o1 + 1]
        range_list = range(range_alice[0], range_alice[1] + 1)
        print('range_list      ', map_list_5_str(range_list))
        # Then alice decode use it's private key d_alice, use U try to return one of the c, and decode back to the x_random_bob
        Yu_list = [((transfer_to_alice + u) ** d_alice) % N_alice for u in range_list]
        print('Yu_list         ', map_list_5_str(Yu_list))

        p_alice_for_bob = 107
        assert p_alice_for_bob < N_alice
        Zu_list = list(map(lambda x: x % p_alice_for_bob, Yu_list))
        print('Zu_list         ', map_list_5_str(Zu_list))

        list_back_to_bob = Zu_list[0:I_alice]
        list_back_to_bob.extend(list(map(lambda x: x + 1, Zu_list[I_alice:])))
        print('list_back_to_bob', map_list_5_str(list_back_to_bob))

        print(list_back_to_bob[J_bob - 1], 'G = x_random_bob % p_alice_for_bob = ', x_random_bob % p_alice_for_bob)
    exit()

    p = 17
    q = 37
    n = p * q
    omega_n = (p-1)*(q-1)
    print('n=', n, '; omega_n=', omega_n)
    e = 17  # random get
    print('e=', e, "; gcd(e, omega_n)=", gcd(e, omega_n))
    for k in range(11300):
        if ((k * e) % omega_n) == 1:
            d = int(k)
            print(d, ',',)
    d = 305
    print("\nd=", d, "; d*e=", d*e, "---> (d * e) mod omega_n =", ((d * e) % omega_n))
    encode_key = (e, n)
    decode_key = (d, n)

    list_num = []
    for i in range(-1200, 1200):
        original_code = i
        after_encode = (original_code ** e) % n
        after_decode = (after_encode ** d) % n
        shift_num = 8
        after_decode_shift = ((after_encode + shift_num) ** d) % n

        list_num.append({'original_code': float(original_code),
                         'after_decode': after_decode,
                         'after_decode_shift': after_decode_shift,
                         'after_encode': after_encode})
    print("....")
    dfp = pd.DataFrame(list_num)[['original_code', 'after_decode', 'after_decode_shift', 'after_encode']]
    print(dfp[(dfp['original_code'] >= 530) & (dfp['original_code'] < 710)])
    print("encode_key=", encode_key)
    print("decode_key", decode_key)
    # exit()


def map_list_5_str(list_in):
    ready_list = list(map(lambda x: '%5s' % str(x), list_in))
    r_str = ','.join(ready_list)
    return '[' + r_str + ']'


# public key of alice as e, and private key as d, total encode space is N
def test_2():
    e_alice = 79
    d_alice = 1019
    N_alice = 3337

    o1 = 1
    o2 = 10

    I_alice = 5
    for J_bob in [5, 7, 3]:
        print("\n****************************************************")
        print("J_bob =", J_bob, "; I_alice =", I_alice)

        assert o1 < I_alice < o2
        assert o1 < J_bob < o2

        # ------------------------------
        x_random_bob = 473  # bob's random number
        c = (x_random_bob ** e_alice) % N_alice
        transfer_to_alice = c - J_bob
        print('transfer_to_alice', transfer_to_alice)

        range_alice = [1, o2 - o1 + 1]
        range_list = range(range_alice[0], range_alice[1] + 1)
        print('range_list      ', map_list_5_str(range_list))

        Yu_list = [((transfer_to_alice + u) ** d_alice) % N_alice for u in range_list]
        print('Yu_list         ', map_list_5_str(Yu_list))

        p_alice_for_bob = 107
        assert p_alice_for_bob < N_alice
        Zu_list = list(map(lambda x: x % p_alice_for_bob, Yu_list))
        print('Zu_list         ', map_list_5_str(Zu_list))

        list_back_to_bob = Zu_list[0:I_alice]
        list_back_to_bob.extend(list(map(lambda x: x + 1, Zu_list[I_alice:])))
        print('list_back_to_bob', map_list_5_str(list_back_to_bob))
        g = x_random_bob % p_alice_for_bob
        g_ = list_back_to_bob[J_bob - 1]
        print('         list[J_bob - 1] = list[' + str(J_bob - 1) + '] =', g_)
        print('G = x_random_bob % p_alice_for_bob =', g)
        print('result:', 'Bob <= Alice' if g >= g_ else 'Bob > Alice')
